package com.ec.auth.security.filter;

import cn.hutool.core.io.IoUtil;
import cn.hutool.json.JSONUtil;
import com.ec.auth.datasource.DynamicDataSourceContextHolder;
import com.ec.auth.datasource.DynamicRoutingDataSource;
import com.ec.common.constant.I18nConstant;
import com.ec.common.core.domain.model.LoginBody;
import com.ec.common.core.redis.RedisCache;
import com.ec.common.utils.CheckUtils;
import com.ec.common.utils.DateUtils;
import com.ec.common.utils.StringUtils;
import com.ec.common.utils.spring.SpringUtils;
import com.ec.saas.domain.MasterTenant;
import com.ec.saas.domain.enums.TenantStatus;
import com.ec.saas.service.IMasterTenantService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class AdminUsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    public AdminUsernamePasswordAuthenticationFilter() {
        // 默认匹配 "/admin/login" 路径的 POST 请求
        super(new AntPathRequestMatcher("/login", "POST"));
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException {

        // 由于前端传递的是 JSON，首先要读取流，转换为字符串，解析出来对象类型
        LoginBody loginBody = JSONUtil.toBean(
                new String(IoUtil.readBytes(request.getInputStream()), StandardCharsets.UTF_8), LoginBody.class);
        // 存入请求头中，这样后面才能使用
        request.setAttribute("LoginBody", loginBody);

        // 获取请求头中的 tenant
        String tenant = request.getHeader("tenant");
        if (StringUtils.isEmpty(tenant)) throw new BadCredentialsException(I18nConstant.TENANT_ID);

        String username = loginBody.getUsername();
        if (StringUtils.isEmpty(username)) throw new BadCredentialsException(I18nConstant.USERNAME_NOT_EXISTS);
        if (StringUtils.isEmpty(loginBody.getPassword()))
            throw new BadCredentialsException(I18nConstant.USER_PASSWORD_NOT_EXISTS);
        if (StringUtils.isEmpty(loginBody.getUuid()))
            throw new BadCredentialsException(I18nConstant.USER_UUID_NOT_EXISTS);

        // 校验验证码
        RedisCache redisCache = SpringUtils.getBean(RedisCache.class);
        String captcha = CheckUtils.validateCaptcha(redisCache, loginBody.getUuid());

        // 抛出异常校验验证码
        if (captcha == null) throw new BadCredentialsException(I18nConstant.USER_JCAPTCHA_EXPIRE);
        else if (!loginBody.getCode().equalsIgnoreCase(captcha))
            throw new BadCredentialsException(I18nConstant.USER_JCAPTCHA_ERROR);

        // 处理租户数据库
        DynamicRoutingDataSource dynamicRoutingDataSource = SpringUtils.getBean(DynamicRoutingDataSource.class);
        if (!dynamicRoutingDataSource.existDataSource(tenant)) {
            // 找不到进行注册租户
            //搜索默认数据库，去注册租户的数据源，下次进来直接session匹配数据源
            IMasterTenantService masterTenantService = SpringUtils.getBean(IMasterTenantService.class);
            MasterTenant masterTenant = masterTenantService.selectMasterTenant(tenant);
            if (masterTenant == null) {
                throw new BadCredentialsException(I18nConstant.TENANT_NOT_EXISTS);
            } else if (TenantStatus.DISABLE.getCode().equals(masterTenant.getStatus())) {
                throw new BadCredentialsException(I18nConstant.TENANT_BLOCKED);
            } else if (masterTenant.getExpirationDate() != null) {
                if (masterTenant.getExpirationDate().before(DateUtils.getNowDate())) {
                    throw new BadCredentialsException(I18nConstant.TENANT_EXPIRE);
                }
            }
            Map<String, Object> map = new HashMap<>();
            map.put("driverClassName", "com.mysql.cj.jdbc.Driver");
            map.put("url", masterTenant.getUrl());
            map.put("username", masterTenant.getUsername());
            map.put("password", masterTenant.getPassword());
            // 设置租户信息
            dynamicRoutingDataSource.addDataSource(tenant, map);

            log.info("已设置租户:{} 连接信息: {}", tenant, masterTenant);
        }
        // 为了单次请求，多次连接数据库的情况，这里设置localThread，AbstractRoutingDataSource的方法去获取设置数据源
        DynamicDataSourceContextHolder.setDataSourceKey(tenant);

        // 获取无状态的验证类
        UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken
                .unauthenticated(loginBody.getUsername(), loginBody.getPassword());
        // 使用认证管理器进行验证
        return this.getAuthenticationManager().authenticate(authRequest);
    }
}
